package com.wanglei.pc.server;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.xerial.snappy.Snappy;
import prometheus.Remote;
import prometheus.Types;
import ru.yandex.clickhouse.BalancedClickhouseDataSource;
import ru.yandex.clickhouse.ClickHouseConnection;
import ru.yandex.clickhouse.ClickHouseStatement;
import ru.yandex.clickhouse.settings.ClickHouseProperties;

import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {


        System.out.println("xxxxxx");

        if (httpObject instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) httpObject;

            // 1 解析uri参数
            String uri = request.uri();
            if (uri.equalsIgnoreCase("/favicon.ico"))
                return;

            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, StandardCharsets.UTF_8);
            log.info("request uti={}", uri);
            for (Map.Entry<String, List<String>> entry : queryStringDecoder.parameters().entrySet()) {
                List<String> value = entry.getValue();
                for (String s : value) {
                    log.info("key={},value={}", entry.getKey(), s);
                }
            }

            // 2 解析get/post
            HttpMethod method = request.method();
            HttpHeaders headers = request.headers();
            String contentType = headers.get("Content-Type").split(":")[0];
            if (contentType.contains(";")) {
                contentType = contentType.substring(0, contentType.indexOf(";"));
            }

            if (method.equals(HttpMethod.GET)) {

                /*
                Content-Encoding: snappy
                Content-Type: application/x-protobuf
                 */

            } else if (method.equals(HttpMethod.POST)) {
                ByteBuf content = ((FullHttpRequest) request).content();
                switch (contentType) {
                    case "application/x-protobuf":
                        byte[] bytes = new byte[content.readableBytes()];
                        content.readBytes(bytes);
                        byte[] uncompress = Snappy.uncompress(bytes);

                        Remote.ReadRequest readRequest = Remote.ReadRequest.parseFrom(uncompress);
                        List<Remote.Query> queriesList = readRequest.getQueriesList();

                        for (Remote.Query query : queriesList) {
                            String sql = buildSql(query);
                            Remote.ReadResponse promeResponse = executeSql(sql);
                            System.out.println();

                            // 将 查询得到的结果返回给prometheus

                        }


                        break;
                    case "application/x-www-form-urlencoded":
                    case "multipart/form-data":
                    default:
                        throw new UnsupportedOperationException("");
                }
            } else {
                System.out.println("only support get/post request");
            }

        } else {
            ReferenceCountUtil.release(httpObject);
        }
    }

    private Remote.ReadResponse executeSql(String sql) {

        Remote.ReadResponse.Builder builder = Remote.ReadResponse.newBuilder();
        Remote.QueryResult.Builder builder1 = Remote.QueryResult.newBuilder();


        String url = "";
        ClickHouseProperties clickHouseProperties = new ClickHouseProperties();
        BalancedClickhouseDataSource dataSource = new BalancedClickhouseDataSource(url, clickHouseProperties);

        try {
            ClickHouseConnection connection = dataSource.getConnection();
            ClickHouseStatement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            Map<String, Types.TimeSeries> res = new HashMap<>();

            while (resultSet.next()) {
                // 计算tags对应的值
                String tags = "zhongguoyidong,fefefgrg";
                Types.TimeSeries timeSeries = null;
                // 如果维度列和值已经存在了，只要添加samples即可
                if (!res.containsKey(tags)) {

                    Types.TimeSeries.Builder builder2 = Types.TimeSeries.newBuilder();
                    List<Types.Label> labelList = new ArrayList<>();
                    List<Types.Sample> sampleList = new ArrayList<>();
                    // todo 这里需要将维度列和值 填充到labelList 中

                    builder2.addAllLabels(labelList);
                    builder2.addAllSamples(sampleList);
                    timeSeries = builder2.build();
                    res.put(tags, timeSeries);

                } else {
                    timeSeries = res.get(tags);
                }

                // 添加samples
                Types.Sample.Builder builder2 = Types.Sample.newBuilder();
                timeSeries.getSamplesList().add(builder2
                        .setTimestamp(resultSet.getLong("ts"))
                        .setValue(resultSet.getDouble("break_cnt")).build());
            }

            // 将该查询的结果封装到QueryResult中
            Remote.QueryResult queryResult = builder1.addAllTimeseries(new ArrayList<Types.TimeSeries>(res.values())).build();
            return builder.addResults(queryResult).build();


        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;

    }

    private String buildSql(Remote.Query query) {
        long startTs = query.getStartTimestampMs();
        long endTs = query.getEndTimestampMs();
        List<Types.LabelMatcher> matchersList = query.getMatchersList();


        // select
        List<String> select = new ArrayList<>();
        select.add("ts");

        // ts
        List<String> where = new ArrayList<>();
        String ts1 = String.format("ts >= %s", startTs);
        String ts2 = String.format("ts < %s", endTs);
        where.add(ts1);
        where.add(ts2);

        // tags
        select.add("tag1");
        select.add("tag2");
        select.add("tag3");


        // where
        for (Types.LabelMatcher labelMatcher : matchersList) {
            if (!"__name__".equalsIgnoreCase(labelMatcher.getName())) {
                Types.LabelMatcher.Type type = labelMatcher.getType();
                String name = labelMatcher.getName();
                String value = labelMatcher.getValue();
                if (Types.LabelMatcher.Type.EQ.equals(type)) {
                    String format = String.format("%s = %s", name, value);
                    where.add(format);
                } else if (Types.LabelMatcher.Type.NEQ.equals(type)) {
                    String format = String.format("%s != %s", name, value);
                    where.add(format);
                } else if (Types.LabelMatcher.Type.RE.equals(type)) {
                    String format = String.format("match(%s,'%s')=1", name, value);
                    where.add(format);
                } else if (Types.LabelMatcher.Type.NRE.equals(type)) {
                    String format = String.format("match(%s,'%s')=0", name, value);
                    where.add(format);
                } else {
                    log.info("query decode failed key={},value={}", name, value);
                }
            } else {
                select.add(labelMatcher.getValue());
            }
        }

        // sql
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("select ");
        for (int i = 0; i < select.size(); i++) {
            if (i == select.size() - 1) {
                stringBuilder.append(select.get(i));
            } else {
                stringBuilder.append(select.get(i)).append(",");
            }
        }

        stringBuilder.append(" from metricsdb.test_tbl where ");
        for (int i = 0; i < where.size(); i++) {
            if (i == where.size() - 1) {
                stringBuilder.append(where.get(i));
            } else {
                stringBuilder.append(where.get(i)).append(" and ");
            }
        }

        stringBuilder.append(" order by ts");

        return stringBuilder.toString();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
